package com.sojson.util.servlet;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.math.BigDecimal;
import java.net.Inet4Address;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerMapping;

import com.alibaba.fastjson.JSONObject;
import com.sojson.constant.Constant;
import com.sojson.constant.ConstantByMap;
import com.sojson.constant.ConstantServlet;
import com.sojson.constant.IpConfig;
import com.sojson.result.interfaces.BeforeBodyWriteInterface;
import com.sojson.util.StringUtil;
import com.sojson.util.file.FileUtil;
import com.sojson.util.filter.FilterUtil;
import com.sojson.util.httpclient.HttpClientUtil;
import com.sojson.util.id.IdUtil;
import com.sojson.util.json.JsonUtil;
import com.sojson.util.text.Convert;

import lombok.extern.slf4j.Slf4j;

/**
 * 客户端工具类
 *
 * @author lyh
 */
@Slf4j
public class ServletUtil {

    /**
     * 获取请求对象
     * 
     * @return
     */
    public static ServletRequest getServletRequest() {
        return getHttpServletRequest();
        // return ((WebSubject)SecurityUtils.getSubject()).getServletRequest();
    }

    /**
     * 获取响应对象
     * 
     * @return
     */
    public static ServletResponse getServletResponse() {
        return getHttpServletResponse();
        // return ((WebSubject)SecurityUtils.getSubject()).getServletResponse();
    }

    /**
     * 获取请求对象
     * 
     * @return
     */
    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
    }

    /**
     * 获取请求对象
     * 
     * @return
     */
    public static HttpServletRequest getHttpServletRequestNo() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (StringUtil.isBlankObject(requestAttributes)) {
            return null;
        }
        return ((ServletRequestAttributes)requestAttributes).getRequest();
    }

    /**
     * 获取响应对象
     * 
     * @return
     */
    public static HttpServletResponse getHttpServletResponse() {
        return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
    }

    /**
     * 获取文件请求对象
     * 
     * @return
     */
    public static MultipartHttpServletRequest getMultipartHttpServletRequest() {
        HttpServletRequest request = getHttpServletRequest();
        MultipartResolver resolver = new CommonsMultipartResolver(request.getServletContext());
        return resolver.resolveMultipart(request);
    }

    /**
     * 请求转发
     * 
     * @param url
     * @throws Exception 
     */
    public static void forword(String url) throws Exception {
        forword(getHttpServletRequest(), getServletResponse(), url);
    }

    /**
     * 请求转发
     * 
     * @param request
     * @param response
     * @param url
     * @throws Exception 
     */
    public static void forword(HttpServletRequest request, ServletResponse response, String url) throws Exception {
        request.getRequestDispatcher(url).forward(request, response);
    }

    /**
     * 重定向
     * 
     * @param url
     * @throws IOException 
     */
    public static void redirect(String url) throws IOException {
        redirect(getHttpServletResponse(), url);
    }

    /**
     * 重定向
     * 
     * @param response
     * @param url
     * @throws IOException 
     */
    public static void redirect(HttpServletResponse response, String url) throws IOException {
        response.sendRedirect(url);
    }

    /**
     * 初始化字符编码
     * 
     * @param request
     * @throws UnsupportedEncodingException 
     */
    public static void initCharacterEncoding(ServletRequest request) throws UnsupportedEncodingException {
        request.setCharacterEncoding(Constant.DEFAULT_ENCODING);
    }

    /**
     * 初始化字符编码
     * 
     * @param response
     */
    public static void initCharacterEncoding(ServletResponse response) {
        response.setCharacterEncoding(Constant.DEFAULT_ENCODING);
        response.setContentType(ConstantServlet.CONTENT_TYPE);
    }

    /**
     * 初始化字符编码
     * 
     * @param response
     * @param response
     * @throws UnsupportedEncodingException 
     */
    public static void initCharacterEncoding(ServletRequest request, ServletResponse response)
        throws UnsupportedEncodingException {
        initCharacterEncoding(request);
        initCharacterEncoding(response);
    }

    /**
     * 获取响应对象
     * 
     * @return
     */
    private static HttpServletResponse getResponse() {
        // 获取HttpServletResponse
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        // 初始化HttpServletResponse
        initHttpServletResponse(response);

        return response;
    }

    /**
     * 向页面打印数据
     * 
     * @param response
     * @param rspData 要打印的数据
     * @throws IOException
     */
    public static void out(ServletResponse response, Object rspData) throws IOException {
        out(ServletUtil.getHttpServletRequest(), response, rspData);
    }

    /**
     * 向页面打印数据
     * 
     * @param request
     * @param response
     * @param rspData 要打印的数据
     * @throws IOException
     */
    public static void out(HttpServletRequest request, ServletResponse response, Object rspData) throws IOException {
        // 初始化ServletResponse
        initServletResponse(response);

        if (isChangeResu(request)) {
            rspData = FilterUtil.BEFORE_BODY_WRITE.BeforeBodyWrite(rspData);
        }

        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.println(objectToJsonAll(rspData));
            out.flush();
        } finally {
            closeStream(out);
        }
    }

    /**
     * 向页面打印数据
     * 
     * @param data 要打印的数据
     * @throws IOException
     */
    public static void outFile(InputStream data) throws IOException {
        outFile(data, IdUtil.uuid());
    }

    /**
     * 向页面打印数据
     * 
     * @param data      要打印的数据
     * @param fileName  下载时的文件名
     * @throws IOException
     */
    public static void outFile(InputStream data, String fileName) throws IOException {
        ServletOutputStream outputStream = null;
        try {
            outputStream = getResponseFile(fileName).getOutputStream();
            write(data, outputStream);
            outputStream.flush();
        } finally {
            closeStream(data, outputStream);
        }
    }

    /**
     * 向页面打印数据
     * 
     * @param bytes 要打印的数据
     * @throws IOException
     */
    public static void outFile(byte[] bytes) throws IOException {
        ServletOutputStream outputStream = null;
        try {
            outputStream = getResponseFile().getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
        } finally {
            closeStream(outputStream);
        }
    }

    /**
     * 向页面打印数据
     * 
     * @param bytes     要打印的数据
     * @param fileName  下载时的文件名
     * @throws IOException
     */
    public static void outFile(byte[] bytes, String fileName) throws IOException {
        ServletOutputStream outputStream = null;
        try {
            outputStream = getResponseFile(fileName).getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
        } finally {
            closeStream(outputStream);
        }
    }

    /**
     * 向页面打印数据
     * 
     * @param data 要打印的数据
     * @throws IOException
     */
    public static void outFileImg(InputStream data) throws IOException {
        ServletOutputStream outputStream = null;
        try {
            outputStream = getResponseFileImg().getOutputStream();
            write(data, outputStream);
            outputStream.flush();
        } finally {
            closeStream(data, outputStream);
        }
    }

    /**
     * 向页面打印数据
     * 
     * @param bytes 要打印的数据
     * @throws IOException
     */
    public static void outFileImg(byte[] bytes) throws IOException {
        ServletOutputStream outputStream = null;
        try {
            outputStream = getResponseFileImg().getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
        } finally {
            closeStream(outputStream);
        }
    }

    /**
     * 向页面打印数据
     * 
     * @param bufferedImage 要打印的数据
     * @throws IOException
     */
    public static void outFileImg(BufferedImage bufferedImage) throws IOException {
        outFileImg(bufferedImage, Constant.GENERATE_IMG_SUFFIX);
    }

    /**
     * 向页面打印数据
     * 
     * @param bufferedImage 要打印的数据
     * @param suffix 图片的格式(后缀)
     * @throws IOException
     */
    public static void outFileImg(BufferedImage bufferedImage, String suffix) throws IOException {
        ServletOutputStream outputStream = null;
        try {
            outputStream = getResponseFileImg().getOutputStream();
            write(bufferedImage, outputStream, suffix);
            outputStream.flush();
        } finally {
            closeStream(outputStream);
        }
    }

    /**
     * 向页面打印数据
     * 
     * @param data 要打印的数据
     * @throws IOException
     */
    public static void outHtml(String data) throws IOException {
        PrintWriter printWriter = null;
        try {
            printWriter = getResponseHtml().getWriter();
            printWriter.write(data);
            printWriter.flush();
        } finally {
            closeStream(printWriter);
        }
    }

    /**
     * 初始化ServletResponse
     * 
     * @param response
     * @throws IOException
     */
    public static void initServletResponse(ServletResponse response) {
        initHttpServletResponse((HttpServletResponse)response);
    }

    /**
     * 初始化HttpServletResponse
     * 
     * @param response
     * @throws IOException
     */
    public static void initHttpServletResponse(HttpServletResponse response) {
        response.addHeader(ConstantServlet.PARAM_NAME_ACCESS_CONTROL_EXPOSE_HEADERS, ConstantByMap.TOKEN_NAME);
    }

    /**
     * 获取响应对象
     * 
     * @return
     */
    private static HttpServletResponse getResponseFile() throws UnsupportedEncodingException {
        // 获取HttpServletResponse
        HttpServletResponse response = getResponse();

        // 初始化内容类型
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + ";charset=" + Constant.DEFAULT_ENCODING);
        return response;
    }

    /**
     * 获取响应对象
     * 
     * @return
     */
    public static HttpServletResponse getResponseFile(String realFileName) throws UnsupportedEncodingException {
        // 获取HttpServletResponse
        HttpServletResponse response = getResponseFile();

        response.setHeader(ConstantServlet.HEADER_DISPOSITION, "attachment; filename=" + percentEncode(realFileName));
        response.addHeader(ConstantServlet.PARAM_NAME_ACCESS_CONTROL_EXPOSE_HEADERS,
            ConstantServlet.HEADER_DISPOSITION);
        return response;
    }

    /**
     * 百分号编码工具方法
     *
     * @param s 需要百分号编码的字符串
     * @return 百分号编码后的字符串
     */
    public static String percentEncode(String s) throws UnsupportedEncodingException {
        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
        return encode.replaceAll("\\+", "%20");
    }

    /**
     * 获取响应对象
     * 
     * @return
     */
    private static HttpServletResponse getResponseHtml() {
        // 获取HttpServletResponse
        HttpServletResponse response = getResponse();

        // 初始化内容类型
        response.setContentType(ConstantServlet.CONTENT_TYPE_TEXT_HTML_UTF_8);

        return response;
    }

    /**
     * 获取响应对象
     * 
     * @return
     */
    private static HttpServletResponse getResponseFileImg() {
        // 获取HttpServletResponse
        HttpServletResponse response = getResponse();

        // 初始化文件信息
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");

        return response;
    }

    /**
     * 判断是否要修改结果
     * 
     * @return
     * @throws IOException
     */
    public static boolean isChangeResu() {
        return isChangeResu(ServletUtil.getHttpServletRequest());
    }

    /**
     * 判断是否要修改结果
     * 
     * @param request
     * @return
     */
    public static boolean isChangeResu(HttpServletRequest request) {
        return BeforeBodyWriteInterface.JSON_STRING
            .equals(getValRequest(request, BeforeBodyWriteInterface.RESPONSE_BODY_TYPE_KEY))
            || BeforeBodyWriteInterface.JSON_STRING_ENCRYPTION
                .equals(getValRequest(request, BeforeBodyWriteInterface.RESPONSE_BODY_TYPE_KEY));
    }

    /**
     * 手动执行过滤器
     * 
     * @param request
     * @param response
     * @return
     */
    public static void doFilter(ServletRequest request, ServletResponse response) {

    }

    /**
     * 从请求中获取参数字符串
     * 
     * @return
     * @throws IOException
     */
    public static String getParamBody() throws IOException {
        HttpServletRequest request = getHttpServletRequest();
        StringBuilder stringBuilder = new StringBuilder();

        InputStreamReader ips = null;
        BufferedReader br = null;
        try {
            ips = new InputStreamReader(request.getInputStream(), Constant.DEFAULT_ENCODING);
            br = new BufferedReader(ips);
            String str = null;
            while (isNotBlankObject(str = br.readLine())) {
                stringBuilder.append(str);
            }
        } finally {
            closeStream(br);
            closeStream(ips);
        }
        return stringBuilder.toString();
    }

    /**
     * 从请求中获取参数
     * 
     * @return
     * @throws IOException
     */
    public static Integer getParamBodyToInt() throws IOException {
        return Integer.valueOf(getParamBody());
    }

    /**
     * 从请求中获取参数
     * 
     * @return
     * @throws IOException
     */
    public static Boolean getParamBodyToBoolean() throws IOException {
        return Boolean.valueOf(getParamBody());
    }

    /**
     * 从请求中获取参数
     * 
     * @return
     * @throws IOException
     */
    public static Double getParamBodyToDouble() throws IOException {
        return Double.valueOf(getParamBody());
    }

    /**
     * 从请求中获取参数
     * 
     * @return
     * @throws IOException
     */
    public static BigDecimal getParamBodyToBigDecimal() throws IOException {
        return new BigDecimal(getParamBody());
    }

    /**
     * 获取String参数
     * 
     * @param key
     * @return
     */
    public static String getParameter(String key) {
        return getHttpServletRequest().getParameter(key);
    }

    /**
     * 获取String参数(给一个默认值防止转换失败,空指针???)
     * 
     * @param key
     * @param defaultValue 默认值
     * @return
     */
    public static String getParameter(String key, String defaultValue) {
        return toStr(getParameter(key), defaultValue);
    }

    /**
     * 获取Integer参数
     * 
     * @param key
     * @return
     */
    public static Integer getParameterToInt(String key) {
        return toInt(getParameter(key));
    }

    /**
     * 获取Integer参数(给一个默认值防止转换失败,空指针???)
     * 
     * @param key
     * @param defaultValue 默认值
     * @return
     */
    public static Integer getParameterToInt(String key, Integer defaultValue) {
        return toInt(getParameter(key), defaultValue);
    }

    /**
     * 获取String参数
     * 
     * @return
     */
    public static Map<String, String[]> getParameterMap() {
        return getHttpServletRequest().getParameterMap();
    }

    /**
     * 获取String参数
     * 
     * @return
     */
    public static Map<String, String> getParameterMapString() {
        Map<String, String[]> parameterMap = getParameterMap();
        if (isBlankObject(parameterMap) || parameterMap.size() < 1) {
            return null;
        }

        HashMap<String, String> hashMap = new HashMap<>();
        Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
        for (Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int length = values.length;
            if (isBlankObject(values) || length < 1) {
                hashMap.put(name, null);
            }

            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < length; i++) {
                stringBuilder.append(values[i]).append(",");
            }
            hashMap.put(name, stringBuilder.substring(0, stringBuilder.length() - 1));
        }
        return hashMap;
    }

    /**
     * 把值放入到当前的Request里
     * 
     * @param key
     * @param value
     */
    public static void setValRequest(String key, Object value) {
        setValRequest(getHttpServletRequest(), key, value);
    }

    /**
     * 把值放入到当前的Request里
     * 
     * @param request
     * @param key
     * @param value
     */
    public static void setValRequest(HttpServletRequest request, String key, Object value) {
        request.setAttribute(key, value);
    }

    /**
     * 从当前的Request里取值
     * 
     * @param key
     * @return
     */
    public static Object getValRequest(String key) {
        return getValRequest(getHttpServletRequest(), key);
    }

    /**
     * 从当前的Request里取值
     * 
     * @param request
     * @param key
     * @return
     */
    public static Object getValRequest(HttpServletRequest request, String key) {
        return request.getAttribute(key);
    }

    /**
     * 删除Request里的值
     * 
     * @param key
     */
    public static void removeValRequest(String key) {
        removeValRequest(getHttpServletRequest(), key);
    }

    /**
     * 删除Request里的值
     * 
     * @param request
     * @param key
     */
    public static void removeValRequest(HttpServletRequest request, String key) {
        request.removeAttribute(key);
    }

    /**
     * 把值放入到当前的Request里
     * 
     * @param key
     * @param value
     */
    public static boolean setValRequestNo(String key, Object value) {
        HttpServletRequest httpServletRequestNo = getHttpServletRequestNo();
        if (StringUtil.isBlankObject(httpServletRequestNo)) {
            return false;
        }
        httpServletRequestNo.setAttribute(key, value);
        return true;
    }

    /**
     * 从当前的Request里取值
     * 
     * @param key
     * @return
     */
    public static Object getValRequestNo(String key) {
        HttpServletRequest httpServletRequestNo = getHttpServletRequestNo();
        if (StringUtil.isBlankObject(httpServletRequestNo)) {
            return null;
        }
        return httpServletRequestNo.getAttribute(key);
    }

    /**
     * 删除Request里的值
     * 
     * @param key
     */
    public static void removeValRequestNo(String key) {
        HttpServletRequest httpServletRequestNo = getHttpServletRequestNo();
        if (StringUtil.isBlankObject(httpServletRequestNo)) {
            return;
        }
        httpServletRequestNo.removeAttribute(key);
    }

    /**
     * 从当前的请求头里取值
     * 
     * @param key
     * @return
     */
    public static String getReqHeader(String key) {
        return getHttpServletRequest().getHeader(key);
    }

    /**
     * 把值放入到响应头中
     * 
     * @param key
     * @param value
     */
    public static void setResHeader(String key, String value) {
        getHttpServletResponse().setHeader(key, value);
    }

    /**
     * 把值放入到响应头中
     * 
     * @param key
     * @return
     */
    public static String getResHeader(String key) {
        return getHttpServletResponse().getHeader(key);
    }

    /**
     * 获取客户端访问的地址
     * 
     * @return
     */
    public static String getRequestUri() {
        return getRequestUri(getHttpServletRequest());
    }

    /**
     * 获取客户端访问的地址
     * 
     * @param request
     * @return
     */
    public static String getRequestUri(HttpServletRequest request) {
        return request.getRequestURI();
    }

    /**
     * 获取客户端访问的地址
     * 
     * @return
     */
    public static String getRequestMapping() {
        return getRequestMapping(getHttpServletRequest());
    }

    /**
     * 获取客户端访问的地址
     * 
     * @param request
     * @return
     */
    public static String getRequestMapping(HttpServletRequest request) {
        String requestMapping = (String)request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        if (requestMapping == null) {
            requestMapping = getRequestUri(request);
            requestMapping =
                IpConfig.contextPathIsExist ? requestMapping.substring(IpConfig.contextPathLength) : requestMapping;
        }
        return requestMapping;
    }

    /**
     * 获取Tomcat抛异常后的访问路径
     * 
     * @return
     */
    public static String getErrMapping() {
        return getErrMapping(getHttpServletRequest());
    }

    /**
     * 获取Tomcat抛异常后的访问路径
     * 
     * @param request
     * @return
     */
    public static String getErrMapping(HttpServletRequest request) {
        return (String)request.getAttribute(ConstantServlet.ERR_PATH_ATTRIBUTE_PARAM_NAME);
    }

    /**
     * 获取请求来源的IP
     * 
     * @return
     */
    public static String getTargetIp() {
        return getTargetIp(getHttpServletRequest());
    }

    /** IP地址查询 */
    public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
    /** IP的所有请求头 */
    private static final String[] HEADERS = {
        //
        "X-Forwarded-For",
        //
        "Proxy-Client-IP",
        //
        "WL-Proxy-Client-IP",
        //
        "HTTP_X_FORWARDED_FOR",
        //
        "HTTP_X_FORWARDED",
        //
        "HTTP_X_CLUSTER_CLIENT_IP",
        //
        "HTTP_CLIENT_IP",
        //
        "HTTP_FORWARDED_FOR",
        //
        "HTTP_FORWARDED",
        //
        "HTTP_VIA",
        //
        "REMOTE_ADDR",
        //
        "X-Real-IP"};
    /** 空IP */
    public static final String UNKNOWN = "unknown";

    /**
     * 判断ip是否为空,空返回true
     * 
     * @param ip
     * @return
     */
    public static boolean isEmptyIp(String ip) {
        return (ip == null || ip.length() == 0 || ip.trim().equals("") || UNKNOWN.equalsIgnoreCase(ip));
    }

    /**
    * 判断ip是否不为空,不为空返回true
    * 
    * @param ip
    * @return
    */
    public static boolean isNotEmptyIp(String ip) {
        return !isEmptyIp(ip);
    }

    /**
     * 获取请求来源的IP
     * 
     * @param request
     * @return
     */
    public static String getTargetIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (isNotEmptyIp(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        // 从其他请求头获取IP
        for (String header : HEADERS) {
            ip = request.getHeader(header);
            if (isNotEmptyIp(ip)) {
                break;
            }
        }
        if (isEmptyIp(ip)) {
            ip = request.getRemoteAddr();
        }
        if (isNotEmptyIp(ip) && ip.contains(",")) {
            ip = ip.split(",")[0];
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        return ip;
    }

    /**
     * 获取本机的主机名
     * 
     * @return
     * @throws Exception
     */
    public static String getLocalHostName() throws Exception {
        return Inet4Address.getLocalHost().getHostName();
    }

    /**
     * 获取本机的局域网ip地址,兼容Linux
     * 
     * @return
     * @throws Exception
     */
    public static String getLocalHostIp() throws Exception {
        return Inet4Address.getLocalHost().getHostAddress();
    }

    /**
     * 获取目标IP的地理位置
     * 
     * @param ip
     * @return
     */
    public static String getRealAddressByIp(String ip) {
        String address = UNKNOWN;
        try {
            Map<String, String> hashMap = new HashMap<>();
            hashMap.put("ip", ip);
            hashMap.put("json", "true");
            String rspStr = HttpClientUtil.doGetByParam(IP_URL, hashMap);
            if (StringUtil.isBlankString(rspStr)) {
                log.error("获取地理位置异常 {}", ip);
                return UNKNOWN;
            }
            JSONObject obj = JSONObject.parseObject(rspStr);
            String region = obj.getString("pro");
            String city = obj.getString("city");
            return String.format("%s %s", region, city);
        } catch (Exception e) {
            log.error("获取地理位置异常 {}", ip);
        }
        return address;
    }

    /**
     * 判断是否是内网IP
     * 
     * @param ip
     * @return
     */
    public static boolean internalIp(String ip) {
        byte[] addr = textToNumericFormatV4(ip);
        return internalIp(addr) || "127.0.0.1".equals(ip);
    }

    /**
     * 判断是否是内网IP
     * 
     * @param ip
     * @return
     */
    private static boolean internalIp(byte[] addr) {
        if (StringUtil.isBlankObject(addr) || addr.length < 2) {
            return true;
        }
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        // 10.x.x.x/8
        final byte SECTION_1 = 0x0A;
        // 172.16.x.x/12
        final byte SECTION_2 = (byte)0xAC;
        final byte SECTION_3 = (byte)0x10;
        final byte SECTION_4 = (byte)0x1F;
        // 192.168.x.x/16
        final byte SECTION_5 = (byte)0xC0;
        final byte SECTION_6 = (byte)0xA8;
        switch (b0) {
            case SECTION_1:
                return true;
            case SECTION_2:
                if (b1 >= SECTION_3 && b1 <= SECTION_4) {
                    return true;
                }
            case SECTION_5:
                switch (b1) {
                    case SECTION_6:
                        return true;
                }
            default:
                return false;
        }
    }

    /**
     * 将IPv4地址转换成字节
     *
     * @param text IPv4地址
     * @return byte 字节
     */
    public static byte[] textToNumericFormatV4(String text) {
        if (text.length() == 0) {
            return null;
        }

        byte[] bytes = new byte[4];
        String[] elements = text.split("\\.", -1);
        try {
            long l;
            int i;
            switch (elements.length) {
                case 1:
                    l = Long.parseLong(elements[0]);
                    if ((l < 0L) || (l > 4294967295L)) {
                        return null;
                    }
                    bytes[0] = (byte)(int)(l >> 24 & 0xFF);
                    bytes[1] = (byte)(int)((l & 0xFFFFFF) >> 16 & 0xFF);
                    bytes[2] = (byte)(int)((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte)(int)(l & 0xFF);
                    break;
                case 2:
                    l = Integer.parseInt(elements[0]);
                    if ((l < 0L) || (l > 255L)) {
                        return null;
                    }
                    bytes[0] = (byte)(int)(l & 0xFF);
                    l = Integer.parseInt(elements[1]);
                    if ((l < 0L) || (l > 16777215L)) {
                        return null;
                    }
                    bytes[1] = (byte)(int)(l >> 16 & 0xFF);
                    bytes[2] = (byte)(int)((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte)(int)(l & 0xFF);
                    break;
                case 3:
                    for (i = 0; i < 2; ++i) {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L)) {
                            return null;
                        }
                        bytes[i] = (byte)(int)(l & 0xFF);
                    }
                    l = Integer.parseInt(elements[2]);
                    if ((l < 0L) || (l > 65535L)) {
                        return null;
                    }
                    bytes[2] = (byte)(int)(l >> 8 & 0xFF);
                    bytes[3] = (byte)(int)(l & 0xFF);
                    break;
                case 4:
                    for (i = 0; i < 4; ++i) {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L)) {
                            return null;
                        }
                        bytes[i] = (byte)(int)(l & 0xFF);
                    }
                    break;
                default:
                    return null;
            }
        } catch (NumberFormatException e) {
            return null;
        }
        return bytes;
    }

    /**
     * 获取HttpSession
     * 
     * @return
     */
    public static HttpSession getHttpSession() {
        return getHttpServletRequest().getSession();
    }

    /**
     * 是否是Ajax异步请求
     *
     * @param request
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        if (accept != null && accept.indexOf("application/json") != -1) {
            return true;
        }

        String xRequestedWith = request.getHeader("X-Requested-With");
        if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
            return true;
        }

        String uri = request.getRequestURI();
        if (inStringIgnoreCase(uri, ".json", ".xml")) {
            return true;
        }

        String ajax = request.getParameter("__ajax");
        return inStringIgnoreCase(ajax, "json", "xml");
    }

    /** 所有控制器的路径添加前缀(为了区分静态资源) */
    public static final String METHOD_PATH = getMethodPath();
    /** 所有控制器的路径添加前缀(为了区分静态资源)是否存在 */
    public static final boolean METHOD_PATH_IS_EXIST = methodPathIsExist();

    /**
     * 获取所有控制器的路径添加前缀(为了区分静态资源)
     * 
     * @return
     */
    private static String getMethodPath() {
        String property = Constant.PROPERTIES.getProperty("so.server.servlet.method-path");
        if (StringUtil.isBlankObject(property) || (property.length() == 1 && property.equals("/"))
            || (property.length() == 2 && property.equals("\\"))) {
            return "";
        }

        if (!property.startsWith("\\") && !property.startsWith("/")) {
            property = "/" + property;
        }
        if (property.endsWith("\\")) {
            property = property.substring(0, property.length() - 2);
        }
        if (property.endsWith("/")) {
            property = property.substring(0, property.length() - 1);
        }

        return property;
    }

    /**
     * 所有控制器的路径添加前缀(为了区分静态资源)是否存在
     * 
     * @return
     */
    private static boolean methodPathIsExist() {
        return METHOD_PATH.length() > 0;
    }

    /**
     * 获取映射全路径
     * 
     * @param mappingUrl    映射路径
     * @return
     */
    public static String getMappingUrl(String mappingUrl) {
        return METHOD_PATH + mappingUrl;
    }

    /**
     * 将输入流内容放到输出流
     * 
     * @param inputStream
     * @param outputStream
     * @throws IOException
     */
    private static void write(InputStream inputStream, OutputStream outputStream) throws IOException {
        FileUtil.write(inputStream, outputStream);
    }

    /**
     * 将输入流内容放到输出流
     * 
     * @param bufferedImage
     * @param outputStream
     * @param suffix 文件类型(后缀)
     * @throws IOException
     */
    private static void write(BufferedImage bufferedImage, OutputStream outputStream, String suffix)
        throws IOException {
        FileUtil.write(bufferedImage, outputStream, suffix);
    }

    /**
     * 判断一个对象是否是空(空对象)
     * 
     * @param obj
     * @return
     */
    private static boolean isBlankObject(Object obj) {
        return StringUtil.isBlankObject(obj);
    }

    /**
     * 判断一个对象是否不是空(空对象)
     * 
     * @param obj
     * @return
     */
    private static boolean isNotBlankObject(Object obj) {
        return StringUtil.isNotBlankObject(obj);
    }

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    private static boolean inStringIgnoreCase(String str, String... strs) {
        return StringUtil.inStringIgnoreCase(str, strs);
    }

    /**
     * 转换为int<br>
     * 如果给定的值为空，或者转换失败，返回默认值<br>
     * 转换失败不会报错
     *
     * @param value        被转换的值
     * @param defaultValue 转换错误时的默认值
     * @return 结果
     */
    private static Integer toInt(Object value, Integer defaultValue) {
        return Convert.toInt(value, defaultValue);
    }

    /**
     * 转换为int<br>
     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>
     * 转换失败不会报错
     *
     * @param value 被转换的值
     * @return 结果
     */
    private static Integer toInt(Object value) {
        return Convert.toInt(value);
    }

    /**
     * 转换为字符串<br>
     * 如果给定的值为null，或者转换失败，返回默认值<br>
     * 转换失败不会报错
     *
     * @param value        被转换的值
     * @param defaultValue 转换错误时的默认值
     * @return 结果
     */
    private static String toStr(Object value, String defaultValue) {
        return Convert.toStr(value, defaultValue);
    }

    /**
     * 关闭字符输入流
     * 
     * @param reader 需要关闭的字符输入流
     * @throws IOException
     */
    private static void closeStream(Reader reader) throws IOException {
        FileUtil.closeStream(reader);
    }

    /**
     * 关闭字符输出流
     * 
     * @param reader 需要关闭的字符输出流
     * @throws IOException
     */
    private static void closeStream(Writer writer) throws IOException {
        FileUtil.closeStream(writer);
    }

    /**
     * 关闭字节输出流
     * 
     * @param outputStream 需要关闭的字节输出流
     * @throws IOException
     */
    private static void closeStream(OutputStream outputStream) throws IOException {
        FileUtil.closeStream(outputStream);
    }

    /**
     * 将对象转换成json字符串(值为空的也解析)
     * 
     * @param data 被转换的对象
     * @return 得到的字符串
     */
    private static String objectToJsonAll(Object data) {
        return JsonUtil.objectToJsonAll(data);
    }

    /**
     * 关闭字节输入输出流
     * 
     * @param inputStream 需要关闭的字节输入流
     * @param outputStream 需要关闭的字节输出流
     * @throws IOException
     */
    private static void closeStream(InputStream inputStream, OutputStream outputStream) throws IOException {
        FileUtil.closeStream(inputStream, outputStream);
    }

}